#include "Server.hpp"


std::unordered_map<uint64_t, ConnPtr> _connections;
uint64_t conn_id = 0;

//这里为了方便测试，我们手动地为普通套接字的回调编写一下！
void HandlerClose(ConnPtr conn){
//关闭套接字的回调：不仅仅是关闭连接，还要先取消关注！
    std::cout << "close the fd : " << conn->Fd() << std::endl;
    //取消关注
    conn->ConnChannel()->DelWriteEventMonitor();
    close(conn->Fd());
}

void OnConnected(ConnPtr conn){
    LOG(LogLevel::DEBUG) << "NEW CONNECTION : %s" << conn.get();
}

void OnMessage(ConnPtr conn, Buffer* buf){
    std::string s = buf->ReadAsString(buf->ReadableSize());
    LOG(LogLevel::DEBUG) << s;
    std::string ret = s + " : hello world";
    conn->Send((char*)ret.c_str(), ret.size());
}

void OnClose(ConnPtr conn){
    LOG(LogLevel::DEBUG) << "CLOSE : " << conn->Fd();
}

void OnAny(ConnPtr conn){
    LOG(LogLevel::DEBUG) << "Any : " << conn->Fd();
}

void DelConn(ConnPtr conn){
    _connections.erase(conn->Id());
}

//这个是listen套接字的读回调，其实就是获取新的连接
//功能就是：获取新的连接，然后对新的连接进行设置(监控、回调等)！
void Acceptor(Channel* lis_ch, EventLoop* el){
    //这里就先不用Socket了！因为这里面用的话就是临时变量，一旦退出函数析构了，自动断开连接了!
    //到时候在其他模块会使用Socket，这里为了测试，先写的原生一点
    int lisfd = lis_ch->Fd();
    int fd = accept(lisfd, nullptr,nullptr);
    if(fd < 0) return; //获取链接都失败了，直接返回就好了！

    //开始设置新连接,这一次的连接就变成了Connection
    ConnPtr conn = std::make_shared<Connection>(el, ++conn_id, fd);
    conn->SetMessageCallback(std::bind(OnMessage, std::placeholders::_1, std::placeholders::_2));
    conn->SetConnectedCallback(std::bind(OnConnected, std::placeholders::_1));
    //conn->SetClosedCallback(std::bind(OnClose, conn));
    //conn->SetAnyEventCallback(std::bind(OnAny, conn));
    

    //设置真正的对上层连接进行释放的接口
    conn->SetServerClosedCallback(std::bind(DelConn, std::placeholders::_1));
    //启动非活跃
    conn->EnableInactiveRelease(2); //设定超时时间10s
    //设置就绪状态
    conn->Establish();
    //将当前连接加入到哈希
    _connections[conn_id] = conn;
    
}


// ./test_svr.exe server_port
int main(int argc, char* argv[]){
    if(argc != 2) return -1;

    srand((unsigned int)time(nullptr));

    //创建套接字
    uint16_t server_port = std::stoi(argv[1]);
    Socket server_socket;
    server_socket.CreateServer(server_port);

    EventLoop loop;
    //专门用于listen套接字的事件管理
    Channel listen_channel(server_socket.Fd(), &loop);
    //对于连接套接字来说，只需要设置一个读事件回调即可！(方便测试)
    listen_channel.ReadCallback_Set(std::bind(Acceptor, &listen_channel, &loop));
    //启动监听套接字的读事件监控
    listen_channel.SetReadEventMonitor();

    while(1){
        loop.Start();
        std::cout << "当前被管理的连接:" << std::endl;
        for(auto& it : _connections){
            std::cout << it.first << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}